package org.fujay.langchain4jserver.infrastructure.persistence.repository;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.fujay.langchain4jserver.domain.application.entity.AppUsageStats;
import org.fujay.langchain4jserver.domain.application.repository.AppUsageStatsRepository;
import org.fujay.langchain4jserver.domain.application.vo.AppId;
import org.fujay.langchain4jserver.domain.application.vo.UsageMetrics;
import org.fujay.langchain4jserver.domain.application.vo.UsageStatsId;
import org.fujay.langchain4jserver.infrastructure.persistence.mybatis.entity.AppUsageStatsPo;
import org.fujay.langchain4jserver.infrastructure.persistence.mybatis.mapper.AppUsageStatsMapper;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 应用用量统计仓储实现
 */
@Repository
@RequiredArgsConstructor
public class AppUsageStatsRepositoryImpl implements AppUsageStatsRepository {

    private final AppUsageStatsMapper usageStatsMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void incrementUsage(AppId appId, LocalDate statDate, UsageMetrics increment) {
        usageStatsMapper.incrementUsageStats(
                appId.value(),
                statDate,
                increment.apiCallCount(),
                increment.llmPromptTokens(),
                increment.llmCompletionTokens(),
                increment.embeddingTokens());
    }

    @Override
    public List<AppUsageStats> findByAppIdAndDateRange(
            AppId appId, LocalDate startDate, LocalDate endDate) {
        LambdaQueryWrapper<AppUsageStatsPo> queryWrapper =
                Wrappers.<AppUsageStatsPo>lambdaQuery()
                        .eq(AppUsageStatsPo::getAppId, appId.value())
                        .between(AppUsageStatsPo::getDate, startDate, endDate)
                        .orderByAsc(AppUsageStatsPo::getDate);
        List<AppUsageStatsPo> pos = usageStatsMapper.selectList(queryWrapper);
        return pos.stream().map(this::convertToDomain).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteByAppId(AppId appId) {
        LambdaQueryWrapper<AppUsageStatsPo> deleteWrapper =
                Wrappers.<AppUsageStatsPo>lambdaQuery().eq(AppUsageStatsPo::getAppId, appId.value());
        usageStatsMapper.delete(deleteWrapper);
    }

    // --- Conversion Methods --- (可移至 Assembler)

    private AppUsageStats convertToDomain(AppUsageStatsPo po) {
        if (po == null) return null;

        AppId appId = new AppId(po.getAppId());
        UsageMetrics metrics =
                new UsageMetrics(
                        po.getRequestCount().intValue(),
                        po.getPromptTokens(),
                        po.getCompletionTokens(),
                        po.getTotalTokens());
        UsageStatsId statsId = (po.getId() != null) ? new UsageStatsId(po.getId()) : null;

        // 使用 AppUsageStats.load 静态方法加载
        return AppUsageStats.load(statsId, appId, po.getDate(), metrics, po.getUpdateTime());
    }

}
